home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / NDK / NDK_3.5 / Tutorials / Printer / English / Applications.doc < prev    next >
Encoding:
Text File  |  1999-10-27  |  18.5 KB  |  473 lines

  1.  
  2. printer.device V44 (OS 3.5)
  3.  
  4. Changes
  5.  
  6. Overview
  7.  
  8. · supports up to 10 units with different settings
  9.  
  10. · supports RTG systems based on the CyberGfx API
  11.  
  12. · simplified and extended handling of errors
  13.  
  14. · drivers can flexibly extended using tag lists
  15.  
  16. · extended support for driver-based color conversion and correction
  17.  
  18. · 24 bit color space (16 mio. colors) for printer drivers
  19.  
  20. · flexible printer settings can be controlled by the driver
  21.  
  22.  
  23. Changes for the printer preferences
  24.  
  25. The new version of printer.device brings some changes to the printer
  26. preferences.
  27.  
  28. 1. printer.device supports 10 units - each unit has its own set of preferences
  29. associated with it, each of which can be set by the user using the "printer"
  30. preferences. Opening printer.device and reading the settings functions the
  31. same as in previous version with the single difference that these actions
  32. can be performed on each of the 10 units. In order to select the unit to
  33. choose there are two possibilities:
  34.  
  35. A. Simple unit selection by number, e.g. as an integer gadget.
  36.  
  37. B. Comfortable selection using a popup menu displaying the names that
  38. the user can assign to each unit. In order to do this, the preference
  39. files ENV:Sys:printer.prefs (for unit 0) and ENV:Sys/printer1.prefs
  40. through ENV:Sys/printer9.prefs must be read. All of these files are
  41. IFF files and may possibly contain a FORM PDEV. This FORM will then
  42. contain the following structure (include file prefs/printertxt.h):
  43. folgende Struktur (Includedatei prefs/printertxt.h):
  44.  
  45. struct PrinterDeviceUnitPrefs
  46. {
  47.     LONG    pd_Reserved[4];
  48.     LONG    pd_UnitNum;
  49.     UBYTE    pd_UnitName[UNITNAMESIZE];
  50. };
  51.  
  52. The pd_UnitNum field contains the unit number, the pd_UnitName filed contains
  53. the symbolic name. However, this string may be empty (pd_UnitName[0] == 0) in
  54. which case a replacement text must be used (e.g. Unit N where N is the actual
  55. unit number).
  56.  
  57. The following program will read the names of all 10 units from the preferences
  58. files and print them to the console. The name will be replaced with "Unit N"
  59. (where N is the unit number) if the user did not specify a name for the unit.
  60.  
  61. /* includes */
  62. #include <dos/dos.h>
  63. #include <libraries/iffparse.h>
  64. #include <prefs/prefhdr.h>
  65. #include <prefs/printertxt.h>
  66.  
  67. /* prototypes */
  68. #include <clib/iffparse_protos.h>
  69. #include <clib/dos_protos.h>
  70. #include <clib/alib_protos.h>
  71. #include <clib/alib_stdio_protos.h>
  72. #include <string.h>
  73.  
  74. BPTR stdout;
  75.  
  76. /*****************************************************************************/
  77.  
  78. #define IFFPrefChunkCnt 2
  79. static LONG IFFPrefChunks[] =
  80. {
  81.     ID_PREF, ID_PRHD,
  82.     ID_PREF, ID_PDEV,
  83. };
  84.  
  85. void ReadUnitName(char *filename, char name[], int unitnum)
  86. {
  87.     BPTR fp;
  88.     BOOL ok;
  89.     struct IFFHandle *iff;
  90.     struct ContextNode *cn;
  91.     struct PrefHeader phead;
  92.     struct PrinterDeviceUnitPrefs pdev;
  93.  
  94.     sprintf(name,"Unit %ld",unitnum);
  95.     if (fp = Open(filename, MODE_OLDFILE))
  96.     {
  97.         if (iff = AllocIFF())
  98.         {
  99.             iff->iff_Stream = fp;
  100.             InitIFFasDOS(iff);
  101.  
  102.             if (!OpenIFF(iff, IFFF_READ))
  103.             {
  104.                 if (!ParseIFF(iff, IFFPARSE_STEP))
  105.                 {
  106.                     cn = CurrentChunk(iff);
  107.                     if (cn->cn_ID == ID_FORM && cn->cn_Type == ID_PREF)
  108.                     {
  109.                         if (!StopChunks(iff, IFFPrefChunks, IFFPrefChunkCnt))
  110.                         {
  111.                             ok = TRUE;
  112.                             while (ok)
  113.                             {
  114.                                 if (ParseIFF(iff, IFFPARSE_SCAN))
  115.                                     break;
  116.                                 cn = CurrentChunk(iff);
  117.                                 if (cn->cn_Type == ID_PREF)
  118.                                 {
  119.                                     switch (cn->cn_ID)
  120.                                     {
  121.                                         case ID_PRHD:
  122.                                             if (ReadChunkBytes(iff, &phead, sizeof(struct PrefHeader)) != sizeof(struct PrefHeader))
  123.                                             {
  124.                                                 ok = FALSE;
  125.                                                 break;
  126.                                             }
  127.                                             if (phead.ph_Version != 0)
  128.                                             {
  129.                                                 ok = FALSE;
  130.                                                 break;
  131.                                             }
  132.                                             break;
  133.                                         case ID_PDEV:
  134.                                             if (ReadChunkBytes(iff, &pdev, sizeof(pdev)) == sizeof(pdev))
  135.                                             {
  136.                                                 if (pdev.pd_UnitName[0])
  137.                                                     strcpy(name,pdev.pd_UnitName);
  138.                                             }
  139.                                             break;
  140.                                         default:
  141.                                             break;
  142.                                     }
  143.                                 }
  144.                             }
  145.                         }
  146.                     }
  147.                 }
  148.                 CloseIFF(iff);
  149.             }
  150.             FreeIFF(iff);
  151.         }
  152.         Close(fp);
  153.     }
  154. }
  155.  
  156. void main(void)
  157. {
  158.     char filename[30];
  159.     char name[UNITNAMESIZE];
  160.     int i;
  161.  
  162.     stdout = Output();
  163.     ReadUnitName("ENV:Sys/printer.prefs",name,0);
  164.     printf("Printer Unit Names:\n 0: %s\n",name);
  165.     strcpy(filename,"ENV:Sys/printerN.prefs");
  166.     for (i = 1; i < 10; i++)
  167.     {
  168.         filename[15] = '0' + i;
  169.         ReadUnitName(filename,name,i);
  170.         printf(" %ld: %s\n",i,name);
  171.     }
  172. }
  173.  
  174. Any application should read this list not only upon start up but also every
  175. time something is printed, e.g. when opening the printer dialog. This enables
  176. the list to reflect any name changes the user might have made in the preferences
  177. since the list was last read.
  178.  
  179. 2. The past has shown that the printer preferences do not provide enough
  180. options. Therefore many printer drivers interpret the settings in a different
  181. way. This can easily confuse the user (e.g. when two identical densities
  182. represent different amounts of ink usage). Drivers are now able to provide
  183. such information to the application which in turn can display it in the
  184. printer settings.
  185.  
  186. In order to achieve this, a distinction between old and new drivers must be
  187. made. New drivers are recognized by their version (>= 44) and the PPCB_EXTENDED
  188. flag in the PrinterExtendedData structure (include devices/prtbase.h). If this
  189. is the case, the driver will include a new field called ped_TagList. This
  190. taglist stores some information that is important for the printer preferences.
  191.  
  192. PRTA_DitherNames: The value of this tag is an array of 3 STRPTRs and
  193. holds the names for the three possible dither settings. Up to now these
  194. always were "Ordered", "Halftone" and "Floyd-Steinberg". The driver can now
  195. assign new names that reflect the way the driver interprets these settings.
  196.  
  197. PRTA_ShadingNames: The value of this tag is an array of 4 STRPTRs and is
  198. used to hold the new names for the 4 possible shading options. In previous
  199. versions these were always "Black & White", "Grey Scale 1", "Colored" and
  200. "Grey Scale 2". This is the actual order, although in the preferences they
  201. usually were re-ordered to "Black & White", "Grey Scale 1", "Grey Scale 2"
  202. and "Colored". The array uses the order first referred to. The driver is
  203. now allowed to assign new names that better reflect its interpretation of
  204. the settings (e.g. for printers that don't support color but several
  205. grey scale qualities).
  206.  
  207. PRTA_ColorCorrect: If the value of this tag is FALSE, the three checkmarks
  208. for red, green and blue correction should always be disabled. This means that
  209. the driver does either not support color correction or that it uses different
  210. settings to control them.
  211.  
  212. PRTA_DensityInfo: The value of this tag is an array of 8 STRPTRs. The first
  213. string is currently unused, the following 7 provided additional information
  214. for the print densities 1 to 7. Many drivers use the density settings not
  215. only to choose the density but also other settings that affect the print
  216. qualitiy (e.g. the amount of ink to use for printing). The strings in this
  217. array are meant to inform the user of such circumstances. The preferences
  218. should of course still report the selected density in DPI (e.g. 300 x 300 DPI)
  219. which can be read from PrinterExtendedData.
  220.  
  221. PRTA_Preferences: If the value of this TAG is TRUE the driver supports a set
  222. of proprietary printer options. If the tag is true, the printer preferences
  223. should enable a button gadget called "Options..." which can be used to edit
  224. the additional options. Further explanation on this topic can be found several
  225. paragraphs below.
  226.  
  227.  
  228. Changes regarding printing
  229.  
  230. Printing of text has remained entirely unchanged.
  231.  
  232. Graphics printing now allows the use of RTG bitmaps. Support is provided
  233. for all RTG system which support the CyberGFX API cybergraphics.library.
  234. If an application previously performed printer ouput using a planar bitmap
  235. or converted an RTG bitmap to a color depth of 12 or 8 bits, it can now
  236. be adapted to directly print RTG bitmaps. For high (16 bits) and true (24 or
  237. 32 bits) color bitmaps a color map need not be specified.
  238.  
  239. The new command PRD_DUMPRPORTTAGS extendeds the old PRD_DUMPRPORT command
  240. by one tag list. Currently 3 tags are defined and implemented:
  241.  
  242. DRPA_SourceHook: The value for this tag must be a pointer to a struct hook.
  243. This hook will be called in order to read the source data. The hook contains
  244. a NULL object and a message that is a pointer to struct DRPSourceMsg.
  245. This structure contains the position and size of the array to read as well
  246. as a pointer to a field of ULONGs into which the data will be written.
  247. This field has the exact size width*height that is contained in the message.
  248. Every pixel will be stored as an ULONG of the form 0x00RRGGBB.
  249.  
  250. Typically the height will be 1 for normal printing while for landscape
  251. printing the width will be 1. Applications are allowed to use special
  252. optimizations for this case but they must always support the general
  253. case as well.
  254.  
  255. If the DRPA_SourceHook is used, neither a RastPort nor a color map need
  256. to be specified.
  257.  
  258. DRPA_AspectX, DRPA_AspectY: Using these tags you can control the aspect ratio
  259. of the graphic. These values superseded those that are normally obtained from
  260. the graphics mode (io_Modes) or the GfxBase. If the printing process suppresses
  261. scaling the aspect ratio will be ignored.
  262.  
  263. Further information of the printer driver is in turn read from the driver's
  264. tag list:
  265.  
  266. PRTA_LeftBorder and PRTA_TopBorder: Most printers have a small margin on the
  267. paper to which they can not print. For modern printers this margin will usually
  268. measure a few millimeters. If an application does not only show the printable
  269. area of the paper but the entire page instead, it can now take this margin into
  270. account: The tags specify the paper margins as inches/1000. This value must
  271. be converted into the appropriate amount of pixels, depending on the print
  272. resolution (LeftBorder*ped_XDPI/1000 or TopBorder*ped_YDPI/1000). Use this
  273. values as the offset for the rastport the bitmap of which contains the entire
  274. page while printing. This will cause the margin to be skipped while printing
  275. and the hardcopy will match the screen display very closely.
  276.  
  277. PRTA_MixBWColor: If the value of this tag is TRUE, the application can
  278. mix black/white and color printing at will. When printing segments an
  279. application that has e.g. a lot of black text and only a few graphics in
  280. the printer output (typical word processor) can significantly speed up the
  281. printing process if segments that only contain black text on white paper
  282. are printed using the black/white mode of the printer, while segments containg
  283. both text and graphics are printed using the color mode. However, some printers
  284. use different cartridges or inks, negating the speed gain or resulting in
  285. poor quality of the hardcopy. Applications should forego this optimization
  286. if the PRTA_MixBWColor has a value of FALSE.
  287.  
  288. One further piece of information is part of ped_PrinterClass and can also
  289. be set for old drivers:
  290.  
  291. PPCB_NOSTRIPE: This flag denotes a printer driver that is not capable of
  292. segmented (or striped) printing. The consequence is that all print data
  293. must be passed to such a driver at once (which is inacceptable, especially
  294. for color output and resolutions of 300 DPI and up) or the source hook
  295. DRPA_SourceHook must be used "intelligently", i.e. when requesting data
  296. through the source hook the data must be created accordingly by the application.
  297.  
  298. Please bear in mind that the source hook will always be called in the
  299. context of the driver. This context is a DOS process with a stack of
  300. currently 4 KByte. Depending on the concept of your application it may
  301. be necessary to use an Exec message within the source hook to return
  302. control to the application for creating a print segment.
  303.  
  304.  
  305. Error handling
  306.  
  307. Error handling can now be left entirely to printer. device. Up to now the
  308. printer.device or the printer driver could only return errors if the respective
  309. error code was specified in exec/error.h or devices/printer.h. Using V44
  310. of printer.device and new drivers new error messages can be returned as well.
  311. The formatting of a localized error message can be performed by printer.device
  312. or the driver while the ouput can also be performed by the printer.device or
  313. the application.
  314.  
  315. The new command PRD_SETERRORHOOK expects an IOPrtErrReq structure for the
  316. IO request:
  317.  
  318. struct IOPrtErrReq {
  319.     struct  Message io_Message;
  320.     struct  Device  *io_Device;     /* device node pointer  */
  321.     struct  Unit    *io_Unit;       /* unit (driver private)*/
  322.     UWORD   io_Command;             /* device command */
  323.     UBYTE   io_Flags;
  324.     BYTE    io_Error;               /* error or warning num */
  325.     struct  Hook *io_Hook;
  326. };
  327.  
  328. The io_Hook field can either contain the value PDHOOK_NONE in order
  329. to disable automatic error handling or PDHOOK_STD in order to use an
  330. easy-requester for displaying the error message or a pointer to a
  331. structure hook. If an I/O operation of the printer.device ends with
  332. an error, that hook will be called. The object contains a pointer to
  333. the I/O request during which the error occured while the message
  334. packet contains a pointer to an PrtErrMsg structure:
  335.  
  336. struct PrtErrMsg {
  337.     ULONG pe_Version; /* Version of this struct */
  338.     ULONG pe_ErrorLevel; /* RETURN_WARN, RETURN_ERROR, RETURN_FAIL */
  339.     struct Window *pe_Window; /* window for EasyRequest() */
  340.     struct EasyStruct *pe_ES;
  341.     ULONG *pe_IDCMP;
  342.     APTR pe_ArgList;
  343. };
  344.  
  345. The pe_Version field containts the value PDHOOK_VERSION (currently 1).
  346. pe_ErrorLevel contains RETURN_WARN, RETURN_ERROR or RETURN_FAIL in order to
  347. reflect the severeness of the error. pe_Window contains a pointer to a
  348. window or NULL, the window should be used in order to use the correct screen
  349. for output. pe_ES contains a readily formatted EasyStruct structure
  350. including the title and text for the error message. pe_IDCMP may contain
  351. a pointer to a longword variable with IDCMP flags that are supposed to close
  352. a requester while pe_ArgList contains a parameter field that must be used
  353. for formatting the error message and the gadgets. All fields can be used
  354. immediately for the EasyRequest() call.
  355.  
  356. The hook can be called in different tasks: either in the task that iniated
  357. the I/O request or the process of the printer.device unit. In the second
  358. the task is always a DOS process, allowing for file output and other DOS
  359. calls. Please note, however, that no stdio is defined for that process.
  360.  
  361. The following source code is a hook that displays the error in an
  362. easy-requester.
  363.  
  364. struct Task *ApplicationTask;
  365.  
  366. int easyRequestHook(struct Hook *, struct IORequest *ior, struct PrtErrMsg *msg)
  367. {
  368.     struct Task *me = ApplicationTask;
  369.     if (me->tc_Node.ln_Type != NT_PROCESS
  370.         || ((struct Process *) me)->pr_WindowPtr != (struct Window *) -1)
  371.     {
  372.         struct Window *window = msg->pe_Window;
  373.         if (!window && me->tc_Node.ln_Type == NT_PROCESS)
  374.             window = ((struct Process *) me)->pr_WindowPtr;
  375.         return EasyRequestArgs(msg->pe_Window, msg->pe_ES, msg->pe_IDCMP, msg->pe_ArgList);
  376.     }
  377.     return 0;
  378. }
  379.  
  380. struct Hook StdErrorHook =
  381. {
  382.     { NULL, NULL },
  383.     (HOOKFUNC) HookEntry,
  384.     (HOOKFUNC) easyRequestHook,
  385.     NULL
  386. };
  387.  
  388. This hook uses a global variable called ApplicatoinTask in order to determine
  389. whether the error message should be suppressed (pt_WindowPtr == -1 in the
  390. case of processes) and which window should be used for EasyRequestArgs in
  391. order for the requester to open on the screen of that window. A similar
  392. approach uses the PDHOOK_STD hook, but that one always refers to the task
  393. that opened the unit.
  394.  
  395. The error hook must be set back to PDHOOK_NONE prior to closing the unit
  396. of the printer device.
  397.  
  398.  
  399. Driver-specfic settings
  400.  
  401. The printer settings of the "Printer" preferences do not suffice for many
  402. modern printers and their drivers. Since version 2.1 AmigaOS has had a
  403. separate preferences editor for the postscript printer driver that allows
  404. more influence on printer output. In order to be able to change such
  405. setting from within an application, three new printers commands appropriate
  406. possibilities for the drivers are provided. In order to support these
  407. possiblities, you must do the following from within your application.
  408.  
  409. 1. Test whether the driver supports proprietary options. In this case
  410. the PRTA_Preferences tag will be TRUE.
  411.  
  412. 2. Provide an "Options..." button in your printer settings. Disable this button
  413. for old drivers and drivers that do not provided proprietary options.
  414.  
  415. 3. When the user click on the button lock the entire interface and use
  416. the PRD_EDITPREFS command via DoIO to open the settings window. The DoIO
  417. will return once the user has finished his changes to the settings.
  418. The error will be PDERR_CANCEL if the user cancelled the dialog, or 0
  419. otherwise (or another error). The PRD_EDITPREFS command expects a
  420. IOPrtPrefsReq structure. This structure contains an additional field
  421. called io_TagList and knows the following tags:
  422.  
  423. PPRA_Window: Pointer to a window that specifies the screen that is to be
  424. locked against all input while the dialog is open.
  425.  
  426. PPRA_Screen: Pointer to a screen in case PPRA_Window is not specified.
  427.  
  428. PPRA_PubScreen: The name of a public screen in case PPRA_Window is not
  429. specified.
  430.  
  431. 4. If the settings made by the user should be saved or if the printer.device
  432. is closed and re-opened between changing the settings, the application must
  433. read the settings using the PRD_READPREFS command. The PRD_READPREFS command
  434. expects an IOStdReq structure. In this context io_Data contains a pointer to
  435. a buffer that is large enough to hold the data, io_Lenght contains the length
  436. of the buffer, io_Offset must be 0. A length of 8 KB should be sufficient for
  437. the most cases - in case the IOERR_BADLENGTH error is returned one should double
  438. the buffer size and try again (until success).
  439.  
  440. LONG buflen = 8192;
  441. LONG err;
  442. for (;;)
  443. {
  444.     if (!(ior->io_Data = AllocVec(buflen,MEMF_PUBLIC)))
  445.     {
  446.         err = PDERR_BUFFERMEMORY;
  447.         break;
  448.     }
  449.     ior->io_Length = buflen;
  450.     ior->io_Offset = 0;
  451.     if ((err = DoIO(ior)) != IOERR_BADLENGTH)
  452.         break;
  453.     FreeVec(ior->io_Data);
  454.     buflen *= 2;
  455. }
  456.  
  457. The number of bytes that were filled in the buffer is returned in io_Actual.
  458. This buffer is absolutely private to the driver. It can only be kept in memory,
  459. copied bytewise or saved to a file.
  460.  
  461. 5. After opening a printer.device unit the settings that were previously
  462. read can be written back. In order to do so, the PRD_WRITEPREFS command
  463. is is used to return the buffer with the preferences to the driver in
  464. an IOStdReq structure. In this case io_Data will point to the buffer,
  465. io_Length denotes the number of filled bytes in the buffer (i.e. it
  466. corresponds to the io_Actual of PRD_READPREFS).
  467.  
  468. If an application saves the settings to a file and re-uses them when it
  469. is next used it is of course possible that the user has changed the driver
  470. for that unit in the meantime. However, the drivers can determine on their
  471. own whether or not the settings are meant for them. Therefore applications
  472. need not worry about this case.
  473.